﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Linq;
using System.Globalization;
using System.Linq;
using System.Windows.Input;
using CommonBase;
using MCDomain.DataAccess;
using MCDomain.Model;
using MContracts.Classes;
using UIShared.Commands;
using MContracts.Controls;
using MContracts.ViewModel.Helpers;
using MediatorLib;
using McUIBased.Commands;

namespace MContracts.ViewModel
{
    /// <summary>
    /// Модель представления для ввода данных об актах по договору
    /// </summary>
    public class ActsViewModel : ContractWorkspaceViewModel
    {
        private BindingList<Act> _actsBindingList;
        private IEnumerable<Stage> _stages;

        public IEnumerable<Schedulecontract> Schedulecontracts
        {
            get { return ContractObject.Schedulecontracts.Where(c => c.Schedule != null); }
        }

        private Schedulecontract _selectedschedule;

        /// <summary>
        /// выбранный КП
        /// </summary>
        public Schedulecontract SelectedSchedule
        {
            get
            {
                return _selectedschedule ?? (_selectedschedule = Schedulecontracts.FirstOrDefault());
            }
            set
            {
                _selectedschedule = value;
                _actsBindingList = null;
                _stages = null;
                OnPropertyChanged(()=>SelectedSchedule);
                OnPropertyChanged(()=>Stages);
                OnPropertyChanged(()=>ActsBindingList);
                OnPropertyChanged(()=>StagePriceWithNDSColumnTitle);
                OnPropertyChanged(()=>StagePriceWithNoNDSColumnTitle);
                OnPropertyChanged(()=>NDSColumnTitle);
                OnPropertyChanged(()=>PrepaymentColumnTitle);
                OnPropertyChanged(()=>TransferColumnTitle);

            }

        }

        public ActsViewModel(IContractRepository repository)
            : base(repository)
        {

            ViewMediator.Register(this);
        }

        public static IList<Act> GetScheduleActs(Schedule schedule)
        {
            if (schedule == null) throw new ArgumentNullException("schedule");
            return (schedule.Stages.Where(x => x.Act != null).Select(x => x.Act).Distinct().ToList());
        }

        public BindingList<Act> ActsBindingList
        {
            get
            {
                if (Stages != null)
                    return _actsBindingList ??
                           (_actsBindingList =
                            new BindingList<Act>(
                                Repository.TryGetContext().Stages.Where(
                                    x => x.Act != null && x.Schedule == SelectedSchedule.Schedule).Select(x => x.Act).
                                    Distinct().ToList()));
                return null;
            }
        }

        public Act SelectedAct { get; set; }

        [ApplicationCommand("Создать акт", "/MContracts;component/Resources/act_add.png")]
        public ICommand CreateActCommand
        {
            get { return new RelayCommand(CreateAct, x => CanCreateAct); }
        }

        

 
        private IEnumerable<Stage> Stages
        {
            get
            {
                if (SelectedSchedule != null)
                {
                    return _stages ??
                           (_stages =
                            SelectedSchedule.Schedule.Stages);
                }
                return null;
            }
        }

        public bool CanCreateAct
        {
            get { return SelectedSchedule != null; }
        }

        [ApplicationCommand("Удалить акт", "/MContracts;component/Resources/act_delete.png", AppCommandType.Сonfirmable, "Выбранный вами акт будет удалён. Продолжить?")]
        public ICommand DeleteActCommand
        {
            get { return new AutoSubmitCommand(DeleteAct, x => CanDeleteAct, Repository); }
        }

        public bool CanDeleteAct
        {
            get { return SelectedAct != null && SelectedAct.Stages.Count == 0 && SelectedAct.Actpaymentdocuments.Count == 0; }
        }

        [ApplicationCommand("Изменить акт", "/MContracts;component/Resources/act_edit.png")]
        public ICommand EditActCommand
        {
            get { return new RelayCommand(EditAct, x => CanEditAct); }
        }



        public bool CanEditAct
        {
            get { return SelectedAct != null; }
        }

        public string GetSumString(Func<Act, decimal> selector )
        {
            if (ActsBindingList == null) return string.Empty;
            return Math.Round(ActsBindingList.Sum(selector), 2).
                        ToString("N2", Currency.National.CI);
        }

        public string SumPure(Func<Act, decimal> selector)
        {
               if (ActsBindingList == null) 
                    return string.Empty;

               return Math.Round(ActsBindingList.Sum(selector), 2).ToString("N2", Currency.National.CI);
        }



        public string SumWithNDS
        {
            get
            {
                return
                    GetSumString(x => x.ActMoney.Factor.National.WithNdsValue);
                               
            }
        }

        public string SumNDS
        {
            get
            {
                return
                    GetSumString(x => x.ActMoney.Factor.National.NdsValue);
                        
            }
        }

        public string SumCredited
        {
            get
            {
                return
                    GetSumString(x => x.CreditedMoneyModel.Factor.National.WithNdsValue);
            
            }
        }

        public string SumTransfer
        {
            get
            {
                return
                    GetSumString(x => x.TransferSumMoney.Factor.National.WithNdsValue);
                   
            }
        }

        public string ActsCount
        {
            get
            {
                if (ActsBindingList != null)
                    return ActsBindingList.Count.ToString(CultureInfo.InvariantCulture);
                return "0";
            }
        }

      
        public bool AutoIncNums
        {
            get;
            set;
        }

        public void CreateAct(object o)
        {
            ShowActDesignerDialog(null);          
        }

        public void CreateActReport(Act act)
        {
            throw new NotImplementedException();
            //ReportCreatorHelper.CreateActReport(act, ContractObject, ReportCreatorHelper.ActReportTemplate.GazpromNiokr);
        }

        public bool CanCreateActReport {
             get  { return (SelectedAct != null);}
        }

        public void DeleteAct(object o)
        {

            ActsBindingList.Remove(SelectedAct);
            OnStatusChanged();
        }

        public event EventHandler<EventParameterArgs<Act>>  RequestShowActDesigner;

        public void OnRequestShowActDesigner(EventParameterArgs<Act> e)
        {
            EventHandler<EventParameterArgs<Act>> handler = RequestShowActDesigner;
            if (handler != null) handler(this, e);
        }


        private void ShowActDesignerDialog(Act act)
        {
           OnRequestShowActDesigner(new EventParameterArgs<Act>(act));
        }

        public void EditAct(object o)
        {
            ShowActDesignerDialog(SelectedAct);       
        }

       
        public event EventHandler StatusChanged;

        public void OnStatusChanged()
        {
            OnPropertyChanged(()=>SumWithNDS);
            OnPropertyChanged(()=>SumNDS);
            OnPropertyChanged(()=>SumCredited);
            OnPropertyChanged(()=>SumTransfer);
            OnPropertyChanged(()=>ActsCount);

            EventHandler handler = StatusChanged;
            if (handler != null)
              handler(this, EventArgs.Empty);
        }

        private string GetColumnTitle(string mainpart)
        {
            if (SelectedSchedule != null) return mainpart + ", " + Currency.National.CI.NumberFormat.CurrencySymbol;
            return mainpart;
        }

        public string StagePriceWithNDSColumnTitle
        {
            get { return GetColumnTitle("Цена с НДС"); }
        }

        public string StagePriceWithNoNDSColumnTitle
        {
            get { return GetColumnTitle("Цена без НДС"); }
        }

        public string NDSColumnTitle
        {
            get { return GetColumnTitle("НДС"); }
        }

        public string PrepaymentColumnTitle
        {
            get { return GetColumnTitle("Зачтено авансом"); }
        }

        public string TransferColumnTitle
        {
            get { return GetColumnTitle("К перечислению"); }
        }

        private ICommand _createactreportcommand;

        [ApplicationCommand("Формировать акт", "/MContracts;component/Resources/document.png")]
        public ICommand CreateActReportCommand
        {
            get { return _createactreportcommand ?? (_createactreportcommand = new RelayCommand(x=>CreateActReport(SelectedAct), x => CanCreateActReport)); }
        }
        #region Overrides of RepositoryViewModel

        public override string Error
        {
            get
            {
                if (ActsBindingList != null)
                {
                    String error = ActsBindingList.Aggregate(String.Empty,
                                                                         (current, act) => current + (act.Error + "\n"));

                    if (error != String.Empty)
                        return error;
                }
                return null;
            }
        }

        internal Act CreateNewAct(ActDesignerViewModel vm)
        {
            var act = vm.Repository.NewAct(vm.CurrentContract);
            if (AutoIncNums)
            {
                act.Num = GetNextActNum();
            }
            return act;

        }

        public static string GetNextActNumber(IList<Act> acts)
        {
            if (acts == null) throw new ArgumentNullException("acts");
            int result;
            if (!acts.Any()) return "1";
            return (acts.Select(x => int.TryParse(x.Num, out result) ? result : 1).Max() + 1).ToString(CultureInfo.InvariantCulture);
        }

        private string GetNextActNum()
        {
            return GetNextActNumber(ActsBindingList);
        }
        /// <summary>
        /// Переопределите для задания логики сохранения изменений в модели
        /// </summary>
        protected override void Save()
        {
            //base.Save();
            //Repository.DebugPrintRepository();
            //Repository.SubmitChanges();
        }

        /// <summary>
        /// Переопределите для проверки возможности сохранения модели
        /// </summary>
        /// <returns></returns>
        protected override bool CanSave()
        {
            return true;
        }

        public void OnErrorChanged()
        {
            ViewMediator.NotifyColleagues(RequestRepository.REQUEST_ERROR_CHANGED, Error);
        }

        #endregion
        [MediatorMessageSink(RequestRepository.REFRESH_ACTS_SCHEDULE, ParameterType = typeof(Act))]
        internal void ReloadActs(Act act)
        {

            var myAct = Repository.TryGetContext().Acts.SingleOrDefault(x => x.Id == act.Id);
            if (myAct != null)
                Repository.Refresh(RefreshMode.OverwriteCurrentValues, myAct);
            _actsBindingList = null;
           OnPropertyChanged(()=>ActsBindingList);
            
        }

        public override string DisplayName
        {
            get
            {
                if (ContractObject!=null) return "Акты " + ContractObject;
                return base.DisplayName;
            }
            
        }
        public override bool IsClosable
        {
            get { return true; }
        }

        public virtual void SendPropertyChanged(string propertyName)
        {
             OnPropertyChanged(propertyName);
        }
    }
}
